package com.cvte.sunkit.ui.window

import android.annotation.SuppressLint
import android.content.res.Resources
import android.graphics.Color
import android.graphics.drawable.Drawable
import android.os.Environment
import android.os.Handler
import android.os.Looper
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.WindowManager
import android.view.WindowManager.LayoutParams
import android.widget.*
import com.cvte.sunkit.App
import com.cvte.sunkit.R
import com.cvte.sunkit.callback.ChartFloatListener
import com.cvte.sunkit.callback.RecordAbnormalListener
import com.cvte.sunkit.callback.RecordListener
import com.cvte.sunkit.callback.StopServiceListener
import com.cvte.sunkit.manage.CpuMonitor
import com.cvte.sunkit.manage.IOMonitor
import com.cvte.sunkit.manage.MemoryMonitor
import com.cvte.sunkit.model.PerfData
import com.cvte.sunkit.ui.base.BaseWindow
import com.cvte.sunkit.manage.DropboxLogcatManager
import kotlinx.coroutines.*

/**
 *  @PackageName com.cvte.sunkit.ui.window
 *  @Description
 *  @Author lixu
 *  @Data 2023/7/21 10:56
 *  @Version 1.0
 */

class MainFloatWindow(private val windowManager: WindowManager) : BaseWindow() {

    private lateinit var mLayoutParams: LayoutParams
    private lateinit var mFloatWindow: View

    private lateinit var mTxtMemory: TextView
    private lateinit var mCpuText: TextView
    private lateinit var mFpsText: TextView
    private lateinit var mIoInText: TextView
    private lateinit var mIoOutText: TextView
    private lateinit var mFpsPlusText: TextView

    private lateinit var mMemAbnormalText: TextView
    private lateinit var mCpuAbnormalText: TextView
    private lateinit var mIoInAbnormalText: TextView
    private lateinit var mIoOutAbnormalText: TextView

    private lateinit var mCrashCntText: TextView
    private lateinit var mAnrCntText: TextView

    private lateinit var mToastMsgView: TextView
    private lateinit var mToastView: View

    private lateinit var mToastSuccessMsgView: TextView
    private lateinit var mToastSuccessView: View

    private lateinit var mPrintText: TextView

    private lateinit var mStopServiceListener: StopServiceListener
    private lateinit var mRecordListener: RecordListener
    private lateinit var mRecordAbnormalListener: RecordAbnormalListener
    private lateinit var mChartFloatListener: ChartFloatListener

    private val mHandler = Handler(Looper.getMainLooper())


    companion object {
        private const val START_ICON = R.drawable.start
        private const val END_ICON = R.drawable.end

        private const val DROPBOX_START_ICON = R.drawable.ic_dropbox_yes
        private const val DROPBOX_END_ICON = R.drawable.ic_dropbox
        private const val TAG = "MainFloatWindow"

        var isRecord = false
        var isDropbox = false
        private var isWindowOpened = false
    }

    fun setStopServiceListener(serviceListener: StopServiceListener) {
        this.mStopServiceListener = serviceListener
    }

    fun setRecordListener(recordListener: RecordListener) {
        this.mRecordListener = recordListener
    }

    fun setRecordAbnormalListener(recordAbnormalListener: RecordAbnormalListener) {
        this.mRecordAbnormalListener = recordAbnormalListener
    }

    fun setChartFloatListener(chartFloatListener: ChartFloatListener) {
        this.mChartFloatListener = chartFloatListener
    }

    @SuppressLint("InflateParams")
    override fun addView() {
        if (!isWindowOpened) {
            LayoutInflater.from(App.mInstance.applicationContext).inflate(R.layout.float_win, null)
                .also { mFloatWindow = it }
            showWindow()
            mLayoutParams = initLayoutParams()
            windowManager.addView(mFloatWindow, mLayoutParams)

            mToastView =
                LayoutInflater.from(App.mInstance.applicationContext).inflate(R.layout.toast, null)
            mToastMsgView = mToastView.findViewById(R.id.txt_msg)

            mToastSuccessView =
                LayoutInflater.from(App.mInstance.applicationContext)
                    .inflate(R.layout.toast_sccess, null)
            mToastSuccessMsgView = mToastSuccessView.findViewById(R.id.txt_msg)
            refresh()
            isWindowOpened = true
            mRecordAbnormalListener.startRecordAbnormalData() // 开始记录异常数据
        }
    }

    /**
     *  每隔16ms刷新1px像素点驱动屏幕帧率
     */
    private fun refresh() {
        GlobalScope.launch(Dispatchers.IO) {
            var cnt = 0
            while (isActive) {
                withContext(Dispatchers.Main){
                    if (cnt % 2 == 0) {
                        mPrintText.setBackgroundColor(Color.RED)
                    }else{
                        mPrintText.setBackgroundColor(Color.BLACK)
                    }
                }
                cnt++
                delay(16)
            }
        }
    }


    override fun removeView() {
        if (isWindowOpened) {
            windowManager.removeView(mFloatWindow)
            isWindowOpened = false
        }
    }

    @Suppress("DEPRECATION")
    @SuppressLint("SetTextI18n")
    override fun updateUI(data: PerfData, resources: Resources) {

        if (MemoryMonitor.isAbnormal()) {
            mTxtMemory.setTextColor(resources.getColor(R.color.red))
            MemoryMonitor.addAbnormalCnt()
        } else {
            mTxtMemory.setTextColor(resources.getColor(R.color.normal))
        }
        if (CpuMonitor.isAbnormal()) {
            mCpuText.setTextColor(resources.getColor(R.color.red))
            CpuMonitor.addAbnormalCnt()
        } else mCpuText.setTextColor(resources.getColor(R.color.normal))
        if (IOMonitor.isInAbnormal()) {
            IOMonitor.addInAbnormalCnt()
            mIoInText.setTextColor(resources.getColor(R.color.red))
        } else {
            mIoInText.setTextColor(resources.getColor(R.color.normal))
        }
        if (IOMonitor.isOutAbnormal()) {
            IOMonitor.addOutAbnormalCnt()
            mIoOutText.setTextColor(resources.getColor(R.color.red))
        } else {
            mIoOutText.setTextColor(resources.getColor(R.color.normal))
        }
        mTxtMemory.text = "内存 ${data.memTotal}MB ${data.memAvail}MB"
        mCpuText.text = "CPU ${data.sysCpuUsage}%"
        mIoInText.text = "读取速率 ${data.inSpeed}MB/s"
        mIoOutText.text = "写回速率 ${data.outSpeed}MB/s"
        mFpsText.text =
            "应用层级绘制帧率 " + data.fpsDataWrapper.fps + "  延迟数 " + data.fpsDataWrapper.junkCount +
                    " \n最长延时 " + data.fpsDataWrapper.maxJunk + "ms 延迟占比 " + data.fpsDataWrapper.junkPercent + "%"
        mFpsPlusText.text = "系统层级合成帧率：${data.fpsPlus}"
        mMemAbnormalText.text = MemoryMonitor.getAbnormalCnt().toString()
        mCpuAbnormalText.text = CpuMonitor.getAbnormalCnt().toString()
        mIoInAbnormalText.text = IOMonitor.getInAbnormalCnt().toString()
        mIoOutAbnormalText.text = IOMonitor.getOutAbnormalCnt().toString()
    }

    @SuppressLint("SetTextI18n")
    private fun showWindow() {

        mTxtMemory = mFloatWindow.findViewById(R.id.txt_memory)
        mCpuText = mFloatWindow.findViewById(R.id.txt_cpu)
        mFpsText = mFloatWindow.findViewById(R.id.txt_fps)
        mIoInText = mFloatWindow.findViewById(R.id.txt_io_in)
        mIoOutText = mFloatWindow.findViewById(R.id.txt_io_out)
        mFpsPlusText = mFloatWindow.findViewById(R.id.txt_fps_plus)

        mMemAbnormalText = mFloatWindow.findViewById(R.id.txt_abnormal_mem_cnt)
        mCpuAbnormalText = mFloatWindow.findViewById(R.id.txt_abnormal_cpu_cnt)
        mIoInAbnormalText = mFloatWindow.findViewById(R.id.txt_abnormal_io_in_cnt)
        mIoOutAbnormalText = mFloatWindow.findViewById(R.id.txt_abnormal_io_out_cnt)

        mCrashCntText = mFloatWindow.findViewById(R.id.txt_crash)
        mAnrCntText = mFloatWindow.findViewById(R.id.txt_anr)

        mPrintText = mFloatWindow.findViewById(R.id.txt_paint)

        val txtMemThreshold = mFloatWindow.findViewById<TextView>(R.id.txt_mem_threshold)
        val seekBarMemThreshold = mFloatWindow.findViewById<SeekBar>(R.id.seeker_mem_threshold)
        seekBarMemThreshold.progress = MemoryMonitor.getThresholdMemory().toInt()
        txtMemThreshold.text = "${MemoryMonitor.getThresholdMemory()}MB"
        seekBarMemThreshold.setOnSeekBarChangeListener(object :
            SeekBar.OnSeekBarChangeListener {
            @SuppressLint("SetTextI18n")
            override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
                // 处理滑动进度的变化
                // 可以根据progress的值来更新对应的数值
                txtMemThreshold.text = "${p1}MB"
                MemoryMonitor.setThresholdMemory(p1.toLong())
                Log.i(TAG, "onProgressChanged: $p1")

            }

            override fun onStartTrackingTouch(p0: SeekBar?) {
                //用户开始触摸SeekBar时的处理
            }

            override fun onStopTrackingTouch(p0: SeekBar?) {
                // 用户停止触摸SeekBar时的处理

            }

        })

        val txtCpuThreshold = mFloatWindow.findViewById<TextView>(R.id.txt_cpu_threshold)
        val seekBarCpuThreshold = mFloatWindow.findViewById<SeekBar>(R.id.seeker_cpu_threshold)
        seekBarCpuThreshold.progress = CpuMonitor.getThresholdCpu().toInt()
        txtCpuThreshold.text = "${CpuMonitor.getThresholdCpu()}%"
        seekBarCpuThreshold.setOnSeekBarChangeListener(object :
            SeekBar.OnSeekBarChangeListener {
            @SuppressLint("SetTextI18n")
            override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
                txtCpuThreshold.text = "$p1%"
                CpuMonitor.setThresholdCpu(p1.toDouble())
            }

            override fun onStartTrackingTouch(p0: SeekBar?) {
            }

            override fun onStopTrackingTouch(p0: SeekBar?) {
            }

        })

        val txtIoInThreshold = mFloatWindow.findViewById<TextView>(R.id.txt_ioIn_threshold)
        val seekBarIoInThreshold = mFloatWindow.findViewById<SeekBar>(R.id.seeker_ioIn_threshold)
        seekBarIoInThreshold.max = 1000
        seekBarIoInThreshold.progress = IOMonitor.getThresholdIOIn().toInt()
        txtIoInThreshold.text = "${IOMonitor.getThresholdIOIn()}MB/s"
        seekBarIoInThreshold.setOnSeekBarChangeListener(object :
            SeekBar.OnSeekBarChangeListener {
            @SuppressLint("SetTextI18n")
            override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
                txtIoInThreshold.text = "${p1}MB/S"
                IOMonitor.setThresholdIOIn(p1.toDouble())
            }

            override fun onStartTrackingTouch(p0: SeekBar?) {
            }

            override fun onStopTrackingTouch(p0: SeekBar?) {
            }

        })

        val txtIoOutThreshold = mFloatWindow.findViewById<TextView>(R.id.txt_ioOut_threshold)
        val seekBarIoOutThreshold =
            mFloatWindow.findViewById<SeekBar>(R.id.seeker_ioOut_threshold)
        seekBarIoOutThreshold.max = 1000
        seekBarIoOutThreshold.progress = IOMonitor.getThresholdIOOut().toInt()
        txtIoOutThreshold.text = "${IOMonitor.getThresholdIOOut()}MB/s"
        seekBarIoOutThreshold.setOnSeekBarChangeListener(object :
            SeekBar.OnSeekBarChangeListener {
            @SuppressLint("SetTextI18n")
            override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
                txtIoOutThreshold.text = "${p1}MB/S"
                IOMonitor.setThresholdIOOut(p1.toDouble())
            }

            override fun onStartTrackingTouch(p0: SeekBar?) {
            }

            override fun onStopTrackingTouch(p0: SeekBar?) {
            }

        })

        val floatExpandIcon =
            mFloatWindow.findViewById<ImageView>(R.id.float_expand_icon) // 展开扩展区域的图片
        val floatExpandArea =
            mFloatWindow.findViewById<LinearLayout>(R.id.float_expand_panel) // 扩展区域
        floatExpandIcon.setOnClickListener {
            if (floatExpandIcon.rotation.toInt() % 360 == 0) {
                floatExpandArea.visibility = View.VISIBLE
            } else {
                floatExpandArea.visibility = View.GONE
            }
            floatExpandIcon.rotation = floatExpandIcon.rotation + 180
        }


        val startRecord = mFloatWindow.findViewById<ImageView>(R.id.start_record) // 开始录制的按钮
        startRecord.setOnClickListener {
            if (!App.canReadAndWriteFile) {
                Log.i(TAG, "showWindow:系统读写文件权限不足，部分数据无法采集，性能数据无法记录")
            } else {
                if (!isRecord) { // 开始录制
                    startRecord.setImageResource(END_ICON)
                    val startTime: Long = System.currentTimeMillis() // 服务启动则开始录制

                    mRecordListener.startRecord(startTime)
                    isRecord = true
                    toastSuccess("记录开始")

                } else {
                    startRecord.setImageResource(START_ICON)

                    val endTime = System.currentTimeMillis() // 主动停止录制
                    mRecordListener.stopRecord(endTime)
                    isRecord = false
                    toastSuccess("记录结束")
                }
            }
        }


        val closeImg = mFloatWindow.findViewById<ImageView>(R.id.close_window) // 关闭浮窗
        closeImg.setOnClickListener {

            mStopServiceListener.onStopFetchDate()
            if (isRecord) { // 正在录制数据但关闭了服务
                startRecord.setImageResource(START_ICON)
                val endTime = System.currentTimeMillis() // 服务销毁则停止录制
                mRecordListener.stopRecord(endTime)
                mRecordAbnormalListener.stopRecordAbnormalData() // 结束异常数据的记录
                isRecord = false
                toastSuccess("记录结束")
            }
            MemoryMonitor.resetAbnormalCnt()
            CpuMonitor.resetAbnormalCnt()
            IOMonitor.resetInAbnormalCnt()
            IOMonitor.resetOutAbnormalCnt()
            mStopServiceListener.onStop()

        }

        val memRadioButton: RadioButton =
            mFloatWindow.findViewById(R.id.memory_radioBtn) // 打开ChatFloatWindow弹窗
        var isRadioButtonSelected = false // 监控内存占用实时展示折线图
        memRadioButton.setOnClickListener {
            if (isRadioButtonSelected) {
                memRadioButton.isChecked = false
                isRadioButtonSelected = false
                mChartFloatListener.hideMemView()
                if (!(ChartFloatWindow.isShowCpuView || ChartFloatWindow.isShowMemView || ChartFloatWindow.isShowIoView)) {
                    mChartFloatListener.removeView()
                }
            } else {
                memRadioButton.isChecked = true
                isRadioButtonSelected = true
                mChartFloatListener.addView()
                mChartFloatListener.showMemView()
            }
        }
        val cpuRadioButton: RadioButton = mFloatWindow.findViewById(R.id.cpu_radioBtn)
        var isCpuRadioButtonSelected = false

        cpuRadioButton.setOnClickListener {
            if (isCpuRadioButtonSelected) {
                cpuRadioButton.isChecked = false
                isCpuRadioButtonSelected = false
                mChartFloatListener.hideCpuView()
                if (!(ChartFloatWindow.isShowCpuView || ChartFloatWindow.isShowMemView || ChartFloatWindow.isShowIoView)) {
                    mChartFloatListener.removeView()
                }
            } else {
                cpuRadioButton.isChecked = true
                isCpuRadioButtonSelected = true
                mChartFloatListener.addView()
                mChartFloatListener.showCpuView()
            }
        }

        val ioInRadioButton: RadioButton = mFloatWindow.findViewById(R.id.ioIn_radioBtn)
        var isIoRadioButtonSelected = false
        ioInRadioButton.setOnClickListener {
            if (isIoRadioButtonSelected) {
                ioInRadioButton.isChecked = false
                isIoRadioButtonSelected = false
                mChartFloatListener.hideIoView()
                if (!(ChartFloatWindow.isShowCpuView || ChartFloatWindow.isShowMemView || ChartFloatWindow.isShowIoView)) {
                    mChartFloatListener.removeView()
                }
            } else {
                ioInRadioButton.isChecked = true
                isIoRadioButtonSelected = true
                mChartFloatListener.addView()
                mChartFloatListener.showIoView()
            }
        }

        val dropboxBtn: ImageView = mFloatWindow.findViewById(R.id.dropbox)
        var mCoroutineScope: CoroutineScope? = null
        dropboxBtn.setOnClickListener {
            isDropbox = if (!isDropbox) {
                dropboxBtn.setImageResource(DROPBOX_START_ICON)
                mCoroutineScope = CoroutineScope(Dispatchers.IO)
                dropboxLog(System.currentTimeMillis(), mCoroutineScope, true)
                true
            } else {
                dropboxBtn.setImageResource(DROPBOX_END_ICON)
                mCoroutineScope?.cancel()
                false

            }
        }
        mFloatWindow.setOnTouchListener(FloatingOnTouchListener(windowManager))
    }

    private fun toastSuccess(msg: String) {
        mHandler.post {
            Toast.makeText(App.mInstance.applicationContext, msg, Toast.LENGTH_SHORT).show()
        }
    }

    @SuppressLint("SetTextI18n")
    private fun dropboxLog(time: Long, mCoroutineScope: CoroutineScope?, tips: Boolean) {
        var destPath: String?
        var tipsFlag = tips
        mCoroutineScope?.launch(Dispatchers.IO) {
            while (isActive) {
                destPath = DropboxLogcatManager.instance?.output(
                    Environment.getExternalStorageDirectory().path + "/sunkit/dropbox.log",
                    time,
                    800 * 1024
                )
                Log.d(TAG, "dropbox output success: $destPath")
                withContext(Dispatchers.Main) {
                    if (destPath == null) {
                        Toast.makeText(
                            App.mInstance.applicationContext,
                            "dropbox记录的日志信息失败",
                            Toast.LENGTH_LONG
                        ).show()
                    } else {
                        mCrashCntText.text =
                            "crash:${DropboxLogcatManager.instance?.getCrashCnt().toString()}"
                        mAnrCntText.text =
                            "anr:${DropboxLogcatManager.instance?.getAnrCnt().toString()}"
                        if (tipsFlag) {
                            Toast.makeText(
                                App.mInstance.applicationContext,
                                "dropbox记录的日志信息保存路径${destPath}",
                                Toast.LENGTH_LONG
                            ).show()
                            tipsFlag = false
                        }

                    }
                }
                delay(5000)
            }
        }
    }
}